package com.github.rxyor.spring.boot.mybatisplus.tenant;

import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Resource;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.schema.Column;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *<p>
 *
 *</p>
 *
 * @author liuyang
 * @date 2019/11/24 周日 21:34:00
 * @since 1.0.0
 */
@Configuration
@EnableConfigurationProperties(MybatisPlusTenantProperties.class)
public class MybatisPlusTenantAutoConfiguration {

    @Resource
    private MybatisPlusTenantProperties properties;

    /**
     * 多租户属于 SQL 解析部分，依赖 MP 分页插件
     */
    @Bean
    @ConditionalOnMissingBean(PaginationInterceptor.class)
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        Boolean enable = Optional.ofNullable(properties)
            .map(MybatisPlusTenantProperties::getEnable)
            .orElse(false);
        if (Boolean.TRUE.equals(enable)) {
            List<ISqlParser> sqlParserList = new ArrayList<>();
            sqlParserList.add(mybatisPlusTenantParser());
            paginationInterceptor.setSqlParserList(sqlParserList);
        }
        return paginationInterceptor;
    }


    private TenantSqlParser mybatisPlusTenantParser() {
        TenantSqlParser tenantSqlParser = new MybatisPlusTenantParser();
        tenantSqlParser.setTenantHandler(tenantHandler());
        return tenantSqlParser;
    }

    private TenantHandler tenantHandler() {
        return new TenantHandler() {
            @Override
            public Expression getTenantId() {
                Long[] tenantIds = Optional.ofNullable(properties)
                    .map(MybatisPlusTenantProperties::getTenantIds)
                    .orElse(new Long[0]);
                if (tenantIds.length == 1) {
                    Long tenantId = Optional.ofNullable(tenantIds[0]).orElseThrow(() ->
                        new IllegalArgumentException("租户ID不能为空, 必须是个有效的Long型"));
                    return new LongValue(tenantId);
                } else if (tenantIds.length > 1) {
                    final InExpression inExpression = new InExpression();
                    inExpression.setLeftExpression(new Column(getTenantIdColumn()));
                    final ExpressionList itemsList = new ExpressionList();
                    final List<Expression> inValues = new ArrayList<>(tenantIds.length);
                    for (Long tenantId : tenantIds) {
                        if (tenantId == null) {
                            throw new IllegalArgumentException("租户ID不能为空, 必须是个有效的Long型");
                        }
                        inValues.add(new LongValue(tenantId));
                    }
                    itemsList.setExpressions(inValues);
                    inExpression.setRightItemsList(itemsList);
                    return inExpression;
                }
                return null;
            }

            @Override
            public String getTenantIdColumn() {
                return Optional.ofNullable(properties)
                    .map(MybatisPlusTenantProperties::getTenantIdColumn)
                    .filter(StringUtils::isNotBlank)
                    .orElseThrow(() -> new IllegalArgumentException("租户ID列名称不能为空"));
            }

            @Override
            public boolean doTableFilter(String tableName) {
                if (StringUtils.isBlank(tableName)) {
                    return true;
                }

                String[] tables = Optional.ofNullable(properties)
                    .map(MybatisPlusTenantProperties::getTables)
                    .orElse(new String[0]);
                if (tables.length == 0) {
                    return false;
                }
                for (String tb : tables) {
                    if (StringUtils.isBlank(tb)) {
                        continue;
                    }
                    String processConfigTable = tb.replaceAll("`", "").trim();
                    String processCurTable = tableName.replaceAll("`", "").trim();
                    if (processConfigTable.equalsIgnoreCase(processCurTable)) {
                        return false;
                    }
                }
                return true;
            }
        };
    }


}
